package com.skiving.cloud.logutils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.skiving.cloud.admin.entity.SysLog;
import com.skiving.cloud.admin.service.SysLogService;
import com.skiving.cloud.auth.constant.AuthConstant;
import com.skiving.cloud.auth.entity.AuthUser;
import com.skiving.cloud.auth.logutils.IpUtils;
import com.skiving.cloud.auth.util.UserUtil;
import com.skiving.cloud.common.utils.ReturnT;
import com.skiving.cloud.common.utils.UuidUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.snack.ONode;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.aspect.Interceptor;
import org.noear.solon.core.aspect.Invocation;
import org.noear.solon.core.handle.Context;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

@Slf4j
public class OperateLogLocalInterceptor implements Interceptor {
    @Inject
    private SysLogService sysLogService;
    /**
     * 拦截
     *
     * @param inv 调用者
     */
    @Override
    public Object doIntercept(Invocation inv) throws Throwable {
        OperateLogLocal operateLog = inv.method().getAnnotation(OperateLogLocal.class);
        Context ctx = Context.current();
        SysLog sysLog = this.recordLog(operateLog, ctx, inv);
        Map<String, Object> methodParam = inv.argsAsMap();
        sysLog.setMethods(inv.getTargetClz().getName() + "." + inv.method().getMethod().getName());
        //参数
        sysLog.setOperateParams(new ObjectMapper().writeValueAsString(methodParam));
        // 执行方法所消耗的时间
        long start = System.currentTimeMillis();
        //如果是系统异常那就直接抛出异常也不需要记录日志，但如果是业务异常，那就用记录这个日志是否成功
        Object proceed = inv.invoke();
        long end = System.currentTimeMillis();
        long time = end - start;
        sysLog.setActionTime(Long.toString(time));
        sysLog.setId(UuidUtil.get32UUID());
        String jsonStr = ONode.stringify(proceed);
        ONode node = ONode.loadStr(jsonStr);
        Integer code = node.exists("code") ? node.get("code").getInt() : null;
        String message = node.exists("message") ? node.get("message").getString() : null;
        if (Objects.equals(ReturnT.SUCCESS_CODE, code)) {
            //执行成功
            sysLog.setStatus(AuthConstant.COMMON_YES_OR_NO_YES);
        } else {
            sysLog.setStatus(AuthConstant.COMMON_YES_OR_NO_NO);
            sysLog.setErrorMessage(message);
        }
        //请求结果
        sysLog.setResult(jsonStr);
        //异步存储，这里用默认线程池，也可以自定义线程池
        CompletableFuture.runAsync(() ->{
                    boolean x = sysLogService.save(sysLog);
                    System.out.println(x);
                }
        );
        return proceed;
    }

    /**
     * 生成最终日志
     *
     * @param annotation 注解
     * @return joinPoint 切面
     */
    private SysLog recordLog(OperateLogLocal annotation, Context ctx, Invocation inv){
        SysLog sysLog = new SysLog();
        // 执行方法所消耗的时间
        sysLog.setBussid(annotation.bussId());
        sysLog.setDescription(annotation.description());
        sysLog.setMethods(annotation.methods());
        sysLog.setFunctionNo(annotation.functionNo());
        sysLog.setModule(annotation.module());
        sysLog.setOperTime(LocalDateTime.now());
        AuthUser user = UserUtil.getCurrentUser();
        if(user != null){
            sysLog.setUserId(user.getId());
        }
        sysLog.setUserIp(IpUtils.getIpAddress(ctx));
        return sysLog;
    }
}
